/*
     Copyright 2007 Joseph M. Ferner

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System.IO;
using log4net;
using OpenServers.Net.Common.FileSystem;
using OpenServers.Net.FtpServer.State;
using System.Collections.Generic;
using System.Text;

namespace OpenServers.Net.FtpServer.Command {
    /// <summary>
    ///     <para>
    ///         <b>NAME LIST (NLST)</b><br/>
    ///         This command causes a directory listing to be sent from
    ///         server to user site.  The pathname should specify a
    ///         directory or other system-specific file group descriptor; a
    ///         null argument implies the current directory.  The server
    ///         will return a stream of names of files and no other
    ///         information.  The data will be transferred in ASCII or
    ///         EBCDIC type over the data connection as valid pathname
    ///         strings separated by &lt;CRLF&gt; or &lt;NL&gt;.  (Again the user must
    ///         ensure that the TYPE is correct.)  This command is intended
    ///         to return information that can be used by a program to
    ///         further process the files automatically.  For example, in
    ///         the implementation of a "multiple get" function.
    ///     </para>
    ///     <para>
    ///         <b>Format</b><br/>
    ///         <code>NLST [&lt;SP&gt; &lt;pathname&gt;] &lt;CRLF&gt;</code>
    ///     </para>
    ///     <para>
    ///         <b>Success:</b>
    ///         <list type="bullet">
    ///             <item><term>125</term><description>Data connection already open; transfer starting.</description></item>
    ///             <item><term>150</term><description>File status okay; about to open data connection.</description></item>
    ///             <item><term>226</term><description>Closing data connection. Requested file action successful (for example, filetransfer or file abort).</description></item>
    ///             <item><term>250</term><description>Requested file action okay, completed.</description></item>
    ///         </list>
    ///     </para>
    ///     <para>
    ///         <b>Errors:</b>
    ///         <list type="bullet">
    ///             <item><term>421</term><description>Service not available, closing control connection.</description></item>
    ///             <item><term>425</term><description>Can't open data connection.</description></item>
    ///             <item><term>426</term><description>Connection closed; transfer aborted.</description></item>
    ///             <item><term>450</term><description>Requested file action not taken. File unavailable (e.g., file busy).</description></item>
    ///             <item><term>451</term><description>Requested action aborted. Local error in processing.</description></item>
    ///             <item><term>500</term><description>Syntax error, command unrecognized.</description></item>
    ///             <item><term>501</term><description>Syntax error in parameters or arguments.</description></item>
    ///             <item><term>502</term><description>Command not implemented.</description></item>
    ///             <item><term>530</term><description>Not logged in.</description></item>
    ///         </list>
    ///     </para>
    /// </summary>
    public class NameListCommand : BaseSendDataCommand {
        private static readonly ILog log = LogManager.GetLogger(typeof(NameListCommand));

        /// <summary>
        /// returns a list of files in the current directory.
        /// </summary>
        public override void PerformCommand(IFtpServer server, FtpState state, string arguments) {
            string filePath;
            if (arguments != null && arguments.Length > 0) {
                filePath = GetFilePath(state, arguments);
            } else {
                filePath = state.CurrentDirectory;
            }
            IDirectory directory = server.FileSystem.GetDirectory(filePath);
            if (directory == null || !directory.Exists) {
                state.Listener.Send(state, server.Messages.Get550(Reason550.FileNotFound));
            } else {
                if (server.SecurityProvider.CanRead(state.User, directory)) {
                    IList<IFileSystemObject> children = directory.GetItems();
                    StringBuilder fileListString = new StringBuilder();
                    foreach (IFileSystemObject child in children) {
                        fileListString.Append(child.Name + "\r\n");
                    }
                    state.Listener.Send(state, server.Messages.Get150(filePath));
                    log.DebugFormat("begin sending [{0}]", filePath);
                    Stream fileListStream = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(fileListString.ToString()));
                    SendData(server, state, fileListStream);
                } else {
                    state.Listener.Send(state, server.Messages.Get550(Reason550.AccessDenied));
                }
            }
        }
    }
}
